package com.cscec5b.inspection.service;

import com.cscec5b.inspection.dto.ManualFormDTO;
import com.cscec5b.inspection.dto.ManualFormItemDTO;
import com.cscec5b.inspection.dto.ManualFormSubmitDTO;
import com.cscec5b.inspection.dto.TaskListItem;
import com.cscec5b.inspection.entity.Task;
import com.cscec5b.inspection.entity.Task.State;
import com.cscec5b.inspection.repository.TaskRepository;
import org.apache.tomcat.util.digester.Rule;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class TaskService {
    private final TaskRepository repo;

    // NEW: 通过配置注入当前库名（information_schema 要用）
    @Value("${spring.datasource.hikari.schema:inspection_db}")
    private String schema;

    public TaskService(TaskRepository repo){ this.repo = repo; }

    public Map<String, Object> list(long userId, String state, Long projectId, String keyword,
                                    int page, int size) {
        // 将TODO/DONE转换为0/1
        String stateVal = "todo".equalsIgnoreCase(state) ? "0" : "1";
        page = Math.max(page, 1);
        size = Math.max(size, 1);
        int offset = (page - 1) * size;

        boolean todoOrderAsc = "0".equals(stateVal); // 待办升序，已办降序

        long total = repo.countTasks(userId, stateVal, projectId, keyword);
        List<TaskListItem> items = repo.findTasks(userId, stateVal, projectId, keyword, offset, size, todoOrderAsc);

        // 翻页功能
        Map<String, Object> resp = new HashMap<>();
        resp.put("page", page);
        resp.put("size", size);
        resp.put("total", total);
        resp.put("items", items);
        return resp;
    }



    public Page<Task> listForUser(Long uid, Object o, Object o1, int i, int i1) {
        return null;
    }

    // ========= 2) 动态表单：类型元数据（集中配置，易扩展） =========

    /** 每种 taskType 的表名、中文标题、前缀约定 */
    public record TypeMeta(String standardTable, String dataTable, String titleCn, String itemPrefix) {}

    // NEW: 目前配置“钢筋原材料检验批”；后续加其它类型只需在此处扩展
    private static final Map<String, TypeMeta> TYPE_META = Map.of(
            "rebar_material", new TypeMeta("standard_rebar_material", "data_rebar_material", "钢筋原材料检验批", "rebar_"),
            "rebar_process", new TypeMeta("standard_rebar_process", "data_rebar_process", "钢筋加工检验批", "rebar_"),
            "rebar_installation", new TypeMeta("standard_rebar_installation", "data_rebar_installation", "钢筋安装检验批", "rebar_"),
            "rebar_connect", new TypeMeta("standard_rebar_connect", "data_rebar_connect", "钢筋连接检验批", "rebar_"),
            "formwork_installation", new TypeMeta("standard_formwork_installation", "data_formwork_installation", "模板安装检验批", "rebar_"),
            "concrete_mix", new TypeMeta("standard_concrete_mix", "data_concrete_mix", "混凝土拌合物检验批", "rebar_"),
            "concrete_construction", new TypeMeta("standard_concrete_construction", "data_concrete_construction", "混凝土施工检验批", "rebar_"),
            "cast_in_situ_structure", new TypeMeta("standard_cast_in_situ_structure", "data_cast_in_situ_structure", "现浇结构外观质量、位置和尺寸偏差检验批", "rebar_")
            // 后续类型在这里加
            // "rebar_process", new TypeMeta("standard_rebar_process", "data_rebar_process", "钢筋加工检验批", "rebar_"),
            // ...
    );

    // NEW: “验收项前缀” → 中文名称（仅用于显示，建议后续落库）
    private static final Map<String, String> PREFIX_LABEL = Map.of(
            "rebar_appearance", "钢筋外观质量",
            "formed_rebar_appearance", "成型钢筋外观质量",
            "formed_rebar_deviation", "成型钢筋尺寸",
            "rebar_connection_parts", "钢筋机械连接套筒、锚固板及预埋件外观质量"
    );

    // NEW: 一组“期望显示顺序 + 模式 → 中文名”的规则（按顺序挑选命中项；regex 忽略大小写）
    private static final List<Rule> DISPLAY_RULES = List.of(
            new Rule("钢筋外观质量",         "(?i)^rebar_appearance(_|$)"),
            new Rule("成型钢筋外观质量",     "(?i)^rebar_(quality_appearance|finished_appearance|quality_look)(_?|$)"),
            new Rule("成型钢筋尺寸偏差",     "(?i)^rebar_(size(_?deviation)?|dimension(_?deviation)?|dim(_?dev)?)(_?|$)"),
            new Rule("钢筋机械连接套筒",     "(?i)^rebar_((mech|mechanic)[a-z_]*conn|connection(_?parts)?|coupler)(_?|$)")
    );

    // NEW: 小规则对象
    private record Rule(String label, String regex) {}

    // NEW: 判断是否为“变体前缀”，例如 *_min / *_max / *_avg 之类，不作为独立验收项目显示
    private boolean isVariantPrefix(String prefix) {
        return prefix.matches(".*_(min|max|avg|median|std)(_|$)");
    }

    // NEW: 依据规则与直配字典，给某个前缀找一个最合适的中文名
    private String labelForPrefix(String pfx) {
        // 1) 直配命中
        if (PREFIX_LABEL.containsKey(pfx)) return PREFIX_LABEL.get(pfx);
        // 2) 规则匹配
        for (Rule r : DISPLAY_RULES) {
            if (pfx.matches(r.regex())) return r.label();
        }
        // 3) 兜底：直接返回原始前缀（方便你发现未覆盖的命名，后续再补规则/映射）
        return pfx;
    }

    // NEW: 根据“期望顺序规则”对找到的前缀做筛选和排序
    private LinkedHashMap<String,String> pickAndOrderPrefixes(Set<String> foundPrefixes) {
        // 先过滤掉 *_min/_max/_avg 等变体
        List<String> base = new ArrayList<>();
        for (String p : foundPrefixes) if (!isVariantPrefix(p)) base.add(p);

        // 按 DISPLAY_RULES 顺序挑选“最贴近的前缀”
        LinkedHashMap<String,String> ordered = new LinkedHashMap<>();
        for (Rule r : DISPLAY_RULES) {
            for (String p : base) {
                if (ordered.containsKey(p)) continue;
                if (p.matches(r.regex())) {
                    ordered.put(p, r.label());
                    break; // 每个规则选一个代表前缀
                }
            }
        }
        // 其他未被规则命中的，按原顺序附加，并做中文名兜底
        for (String p : base) {
            if (!ordered.containsKey(p)) ordered.put(p, labelForPrefix(p));
        }
        return ordered;
    }

    // ========= 3) 动态表单：读取 & 组装 Schema =========

    private static List<String> parseInspectItemsZhList(Object raw){
        if (raw == null) return List.of();
        String s = (raw instanceof byte[])
                ? new String((byte[]) raw, StandardCharsets.UTF_8)
                : String.valueOf(raw);
        if (s == null || (s = s.trim()).isEmpty()) return List.of();

        // 优先按 JSON 数组解析（支持单引号 JSON）
        try {
            String norm = s;
            if (norm.startsWith("[") && norm.endsWith("]") && norm.indexOf('"') < 0 && norm.indexOf('\'') >= 0) {
                norm = norm.replace('\'', '"');
            }
            com.fasterxml.jackson.databind.ObjectMapper om = new com.fasterxml.jackson.databind.ObjectMapper();
            List<String> arr = om.readValue(norm, new com.fasterxml.jackson.core.type.TypeReference<List<String>>(){});
            List<String> out = new ArrayList<>();
            for (String it : arr) {
                if (it == null) continue;
                // 若元素内部又用“；、，,”连接，二次拆分
                for (String p : it.split("[,，;；、]")) {
                    p = p.trim();
                    if (!p.isEmpty()) out.add(p);
                }
            }
            return out;
        } catch (Exception ignore) { /* 继续兜底 */ }

        // 兜底：整串按“；、，,”拆分
        List<String> out = new ArrayList<>();
        for (String p : s.split("[,，;；、]")) {
            p = p.replaceAll("^[\\[\\]\"]+|[\\[\\]\"]+$","").trim();
            if (!p.isEmpty()) out.add(p);
        }
        return out;
    }

    // TaskService.java 中替换 loadManualForm(...)
    public ManualFormDTO loadManualForm(long taskId, long userId){
        // 装配表头
        var header = repo.findTaskHeader(taskId);
        String taskType = String.valueOf(header.get("task_type"));
        String taskLocation  = String.valueOf(header.get("task_location"));
        Integer failResample = header.get("fail_resample") == null ? null : ((Number)header.get("fail_resample")).intValue();
        String projectName  = String.valueOf(header.get("project_name"));
//        String taskLocation = String.valueOf(header.get("task_location"));
        String taskName     = (org.springframework.util.StringUtils.hasText(taskLocation) ? taskLocation + "-" : ""); //+ meta.titleCn();
        boolean isResample   = failResample != null && failResample == 1;
        var meta = TYPE_META.get(taskType);
        if (meta == null) throw new IllegalArgumentException("不支持的任务类型: " + taskType);


        // ★ 读取任务指定的“仅展示这些项目”
        List<String> allowZhInOrder = parseInspectItemsZhList(header.get("inspect_items"));
        List<String> userAllowedZh = repo.listUserAllowedInspectionItems(taskId, userId);

        // ③ 融合策略：
        //    - 若任务配置了清单 → 取“有序交集”（以任务配置顺序为准）
        //    - 若任务未配置清单 → 直接用用户参与清单
        if (!userAllowedZh.isEmpty()) {
            allowZhInOrder = userAllowedZh.stream().map(String::trim).toList();
        }

        // 映射表：该 task_type 下的所有可用项（item_en + item_zh + hasPhoto/hasPdf）
        var allMapItems = Optional.ofNullable(repo.listTypeItems(taskType)).orElse(List.of());

        // ★ 若任务指定了清单，就严格按清单过滤并保序；未指定（null/空）再展示全部
        List<TaskRepository.TypeItem> finalItems;
        if (!allowZhInOrder.isEmpty()) {
            Map<String, TaskRepository.TypeItem> byZh =
                    allMapItems.stream()
                            .filter(m -> m.itemZh != null)
                            .collect(Collectors.toMap(m -> m.itemZh.trim(), m -> m, (a, b)->a, LinkedHashMap::new));
            finalItems = new ArrayList<>();
            for (String zh : allowZhInOrder) {
                TaskRepository.TypeItem m = byZh.get(zh.trim());
                if (m != null) finalItems.add(m);
                // 没配到映射表的中文名会被忽略；如需提醒，在这里打 warn
                // else log.warn("taskId={} inspect_items 中的 '{}' 未在映射表配置", taskId, zh);
            }
        } else {
            finalItems = allMapItems; // 没指定才展示全部
        }

        // 一次性取列清单和数据
        var stdCols  = repo.listColumns(schema, meta.standardTable());
        var dataCols = repo.listColumns(schema, meta.dataTable());
        var stdRow   = repo.loadStandardRow(meta.standardTable());
        var dataRow  = repo.loadDataRow(meta.dataTable(), taskId);

        // 先把 detail 表一次性拉出来
        Map<String, Map<String, Object>> detailMap = repo.loadDetailOriginalByTask(taskId);


        List<ManualFormItemDTO> items = new ArrayList<>();
        for (var m : finalItems) {
            String key = m.itemEn; // 与 standard_/data_ 表前缀一致

            ManualFormItemDTO it = new ManualFormItemDTO();
            it.setKeyPrefix(key);
            it.setTitle(m.itemZh);
            it.setItemType(m.itemType);

            it.setTaskLocation(taskLocation);      // ★ NEW #4
            it.setResample(isResample);            // ★ NEW #3

            // 标准（只读）
            it.setRequire(    TaskRepository.asStr(stdRow, key + "_require"));
            it.setSampleTotal(TaskRepository.asInt(stdRow, key + "_sample_total"));
            it.setMinNumber(  TaskRepository.asInt(stdRow, key + "_min_number"));

            // 数据（可写）
            it.setNumber( TaskRepository.asInt(dataRow, key + "_number"));
            it.setRecord( TaskRepository.asStr(dataRow, key + "_record"));
            it.setResult( TaskRepository.asStr(dataRow, key + "_result"));

            boolean hasPhoto = m.hasPhoto || dataCols.contains(key + "_photo");
            boolean hasPdf   = m.hasPdf   || dataCols.contains(key + "_pdf");
            it.setHasPhoto(hasPhoto);
            it.setHasPdf(hasPdf);
            if (hasPhoto) it.setPhotoUrl(TaskRepository.asStr(dataRow, key + "_photo"));
            if (hasPdf)   it.setPdfUrl(  TaskRepository.asStr(dataRow, key + "_pdf"));

            Map<String, Object> d = detailMap.get(m.itemZh);  // 以中文名对齐
            if (d != null) {
                Integer checkAmount  = TaskRepository.asInt(d, "check_amount");
                Integer passedAmount = TaskRepository.asInt(d, "passed_amount");
                Integer isPassed     = TaskRepository.asInt(d, "is_passed");
                String  checkRecord  = TaskRepository.asStr(d, "check_record");
                String  deviceRecs   = TaskRepository.asStr(d, "device_records");
                String  inspectPart  = TaskRepository.asStr(d, "inspect_part");
                String collector = TaskRepository.asStr(d, "collector");
                if (collector != null && !collector.isBlank()) it.setCollector(collector);

                // 通用覆盖：已有值优先 detail 表（若 data_* 是空）
                if (it.getNumber() == null) it.setNumber(checkAmount);
                if (it.getRecord() == null || it.getRecord().isBlank()) {
                    // type3 优先设备记录
                    if (Objects.equals(m.itemType, 3) && deviceRecs != null) it.setRecord(deviceRecs);
                    else if (checkRecord != null) it.setRecord(checkRecord);
                }

                // type1：is_passed → result
                if (Objects.equals(m.itemType, 1) && it.getResult() == null) {
                    if (isPassed != null) it.setResult(isPassed == 1 ? "合格" : "不合格");
                }

                // type2：passed_amount → passCount，计算 passRate
                if (Objects.equals(m.itemType, 2)) {
                    if (it.getPassCount() == null) it.setPassCount(passedAmount);
                    Integer n = it.getNumber(), p = it.getPassCount();
                    if (n != null && n > 0 && p != null) {
                        int pct = Math.round(p * 100f / n);
                        it.setPassRate(pct + "%");
                        if (it.getRecord() == null || it.getRecord().isBlank()) {
                            it.setRecord("实抽" + n + "件，合格" + p + "件，合格率" + pct + "%");
                        }
                    }
                }

                // type3：inspect_part → position
                if (Objects.equals(m.itemType, 3)) {
                    if (it.getPosition() == null || it.getPosition().isBlank()) {
                        it.setPosition((inspectPart != null && !inspectPart.isBlank()) ? inspectPart : taskLocation);
                    }
                    it.setReadOnly(true);
                }
            }
            items.add(it);
        }

        ManualFormDTO dto = new ManualFormDTO();
        dto.setTaskId(((Number)header.get("task_id")).longValue());
        dto.setProjectId(((Number)header.get("project_id")).longValue());
        dto.setProjectName(projectName);
        dto.setTaskName(taskName);
        dto.setTaskType(taskType);
        dto.setItems(items);
        return dto;
    }


    // ========= 4) 动态表单：保存 =========

    public void saveManualForm(long taskId, String taskType, ManualFormSubmitDTO body) {
        var meta = TYPE_META.get(taskType);
        if (meta == null) throw new IllegalArgumentException("不支持的任务类型: " + taskType);

        // 仅写入数据表中真实存在的列
        List<String> dataCols = repo.listColumns(schema, meta.dataTable());

        Map<String,Object> values = new LinkedHashMap<>();
        for (ManualFormItemDTO it : body.getItems()) {
            putIfPresent(values, dataCols, it.getKeyPrefix() + "_number", it.getNumber());
            putIfPresent(values, dataCols, it.getKeyPrefix() + "_record", it.getRecord());
            putIfPresent(values, dataCols, it.getKeyPrefix() + "_result", it.getResult());
            if (StringUtils.hasText(it.getPhotoUrl())) putIfPresent(values, dataCols, it.getKeyPrefix() + "_photo", it.getPhotoUrl());
            if (StringUtils.hasText(it.getPdfUrl()))   putIfPresent(values, dataCols, it.getKeyPrefix() + "_pdf", it.getPdfUrl());

            String itemZh = it.getTitle();
            Integer t = it.getItemType();
            Integer checkAmount = it.getNumber();
            Integer passedAmount = null;
            Integer isPassed = null;
            String  checkRecord = it.getRecord();
            String  deviceRecords = null;
            String  inspectPart = null;
            String  collector    = it.getCollector();

            if (Objects.equals(t, 1)) {
                // 直接观察
                isPassed = "合格".equals(it.getResult()) ? 1 : ("不合格".equals(it.getResult()) ? 0 : null);
            } else if (Objects.equals(t, 2)) {
                // 观察合格率
                passedAmount = it.getPassCount();
            } else if (Objects.equals(t, 3)) {
                // 设备导入
                inspectPart   = it.getPosition();
                deviceRecords = it.getRecord();    // 设备情况记录
            }

            // 写回 detail 表（兼容 insert/update）
            repo.upsertDetailOriginal(taskId, taskType, itemZh, inspectPart, checkAmount, passedAmount,
                    isPassed, checkRecord, deviceRecords, collector);
        }
        repo.upsertDataRow(meta.dataTable(), taskId, values);
    }

    private static void putIfPresent(Map<String,Object> m, List<String> exists, String col, Object val){
        if (exists.contains(col)) m.put(col, val);
    }
}

